package com.service.impl;

import com.service.SearchService;
import com.utils.ConnectionUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


public class SearchServiceImpl implements SearchService {
    @Override
    public void termQuery(String index, String field, String value) throws Exception {

//        RestHighLevelClient client = ConnectionUtils.getClient();
////        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
////        searchSourceBuilder.query(QueryBuilders.termQuery(field,value));
////        SearchRequest request = new SearchRequest(index).source(searchSourceBuilder);
////        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//        SearchResponse response = client.search(new SearchRequest(index).source(new SearchSourceBuilder().query(QueryBuilders.termQuery(field, value))), RequestOptions.DEFAULT);
        SearchResponse response = baseSearch(index, QueryBuilders.termQuery(field, value));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }


    @Override
    public void termsQuery(String index, String field, String... values) throws Exception {
//        RestHighLevelClient client = ConnectionUtils.getClient();
//        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        searchSourceBuilder.query(QueryBuilders.termsQuery(field, values));
//        SearchRequest request = new SearchRequest(index).source(searchSourceBuilder);
//        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        SearchResponse response = baseSearch(index, QueryBuilders.termsQuery(field, values));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void matchAll(String index) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.matchAllQuery());
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void matchQuery(String index, String field, String value) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.matchQuery(field, value));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });

    }

    @Override
    public void matchQueryWithOperator(String index, String field, String value, Operator operator) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.matchQuery(field, value).operator(operator));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void multiMatch(String index, String value, String... filed) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.multiMatchQuery(value, filed));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void idsQuery(String index, String... ids) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.idsQuery().addIds(ids));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void prefixQuery(String index, String filed, String value) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.prefixQuery(filed, value));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void FuzzyQuery(String index, String filed, String value, int prefixLength) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.fuzzyQuery(filed, value).prefixLength(prefixLength));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void wildcardQuery(String index, String filed, String value) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.wildcardQuery(filed, value));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void rangeQuery(String index, String filed) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.rangeQuery(filed).gt(5).lt(10));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void regexpQuery(String index, String filed, String reg) throws Exception {
        SearchResponse response = baseSearch(index, QueryBuilders.regexpQuery(filed, reg));
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void createScroll(String index, QueryBuilder queryBuilder, int size, String time) throws Exception {
        RestHighLevelClient client = ConnectionUtils.getClient();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //设置查询条件
        searchSourceBuilder.query(queryBuilder)
                .size(size);//设置期望的返回的条数
        //创建查询的请求对象
        SearchRequest request = new SearchRequest(index).source(searchSourceBuilder)
                .scroll(time);//开启滚动查询,并设置滚动的有效期
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        System.err.println(response.getScrollId());
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void scrollQuery(String scrollId, String time) throws Exception {
        RestHighLevelClient client = ConnectionUtils.getClient();
        SearchResponse response = client.scroll(new SearchScrollRequest(scrollId).scroll(time), RequestOptions.DEFAULT);
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void deleteByQuery(String index, QueryBuilder queryBuilder) throws Exception {
        RestHighLevelClient client = ConnectionUtils.getClient();
        BulkByScrollResponse response = client.deleteByQuery(new DeleteByQueryRequest(index).setQuery(queryBuilder), RequestOptions.DEFAULT);
        System.err.println(response.toString());
    }

    @Override
    public void booleanQuery(String index, BoolQueryBuilder boolQueryBuilder) throws Exception {
        SearchResponse response = baseSearch(index, boolQueryBuilder);
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void boostingQuery(String index, BoostingQueryBuilder boostingQueryBuilder) throws Exception {
        SearchResponse response = baseSearch(index, boostingQueryBuilder);
        Arrays.stream(response.getHits().getHits()).forEach(searhHit -> {
            System.err.println(searhHit.getSourceAsString());
        });
    }

    @Override
    public void highLightQuery(String index, QueryBuilder queryBuilder, HighlightBuilder highlightBuilder) throws Exception {
        RestHighLevelClient client = ConnectionUtils.getClient();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //设置查询条件
        searchSourceBuilder.query(queryBuilder);
        //设置高亮的设置
        searchSourceBuilder.highlighter(highlightBuilder);
        //创建查询的请求对象
        SearchRequest request = new SearchRequest(index).source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

//        List<Map> mapList = new ArrayList<>();
//        for (SearchHit searchHit : response.getHits().getHits()) {
//            //获取原始数据
//            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
//            //获取到高亮的数据
//            HighlightBuilder.Field field = highlightBuilder.fields().get(0);//高亮的字段//从结果中获取高亮字段
//            HighlightField highlightField = searchHit.getHighlightFields().get(field);
//            //获取收到所有的高亮的数据的数组
//            Text[] fragments = highlightField.getFragments();
//            //如果有高亮
//            if (fragments == null && fragments.length > 0) {
//                //高亮发内容
//                String highLightContent = fragments[0].string();
//                //用高亮的数据替换掉原始的数据
//                sourceAsMap.put(field.name(), highLightContent);
//            }
//            mapList.add(sourceAsMap);
//        }
//
        //遍历每一条结果,将高亮数据替换掉原始数据后将数据放到一个集合中
        List<Map<String, Object>> list = Arrays.stream(response.getHits().getHits())
                .map(searchHit -> {//数据转换
                    //获取原始数据
                    Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
                    //获取到高亮的数据
                    HighlightBuilder.Field field = highlightBuilder.fields().get(0);//高亮的字段//从结果中获取高亮字段
                    //因为高亮的数据可能比较多,所以我们要确认获取哪个高亮数据,我们以我们想要的高亮字段对应的数据为准
                    HighlightField highlightField = searchHit.getHighlightFields().get(field.name());
                    if (highlightField != null) {
                        //获取收到所有的高亮的数据的数组
                        Text[] fragments = highlightField.getFragments();
                        //如果有高亮
                        if (fragments != null && fragments.length > 0) {
                            //高亮发内容
                            String highLightContent = fragments[0].string();
                            //用高亮的数据替换掉原始的数据
                            sourceAsMap.put(field.name(), highLightContent);
                        }
                    }
                    return sourceAsMap;
                }).collect(Collectors.toList());//将数据保存到集合中

        System.err.println(list);
    }

    /**
     * 封装有通用查询的方法,只需要传递不同的查询条件即可
     *
     * @param index
     * @param queryBuilder
     * @return
     * @throws Exception
     */
    private SearchResponse baseSearch(String index, QueryBuilder queryBuilder) throws Exception {
        RestHighLevelClient client = ConnectionUtils.getClient();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //设置查询条件
        searchSourceBuilder.query(queryBuilder);
        //创建查询的请求对象
        SearchRequest request = new SearchRequest(index).source(searchSourceBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        return response;
    }


}




















